//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using OpenLS.Core;
using OpenLS.Spreadsheet.Expressions;

namespace OpenLS.Spreadsheet
{
	partial class Cell
	{
		private Expression _expression
		{
			get { return CellData.GetExpression(_cellData); }
			set { _cellData = CellData.SetExpression(_cellData, value); }
		}

		private object _cellData;

		internal Expression Expression
		{
			get { return _expression; }
			set
			{
				if (value == _expression)
					return;
				onPreviewValueChanged();
				SetExpressionRecalc(value, Workbook.CalculationProperties.CalculationMode != CalculationMode.Manual);
			}
		}

		internal void setExpressionValue(Expression value)
		{
			Contract.Requires(!(value is ConstantExpression));
            if (value == _expression)
                return;
			var oldExpression = _expression;
			this.Worksheet.NotifyPreviewFormulaChanged(this, oldExpression, value);

			_expression = value;
			this.Worksheet.NotifyFormulaChanged(this, oldExpression, value);
		}

		internal void SetExpressionRecalc(Expression value, bool recalc)
		{
			if (UndoEnabled)
				Workbook.AddUndoUnit(new SetCellExpressionUndoUnit(this));

			ForgetDependents();
			if (HasExtraData)
				ExtraData.ForgetRangeDependencies();
			if (value is ConstantExpression)
			{
				//_expression = null;
				bool forceString = false;
				if (value is StringConstantExpression)
					forceString = ((StringConstantExpression) value).ForceString;
				if (value is DoubleConstantExpression)
					value = new StringConstantExpression(((DoubleConstantExpression) value).OriginalString);
				object v = ((ConstantExpression) value).Value;
				if (value is TimeConstantExpression)
				{
					DateTime dt = ((TimeConstantExpression) value).TypedValue;
					DateTime zd = Worksheet.ZeroDate;
					dt = new DateTime(zd.Year, zd.Month, zd.Day, dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
					SetValueAndFormat(dt, false);
					string originalString = ((TimeConstantExpression) value).OriginalString.ToLower();
					bool hasAmPm = originalString.Contains("am") || originalString.Contains("pm");
					if (dt.Second == 0)
						Format = Format.Parse(hasAmPm?"h:mm AM/PM":"h:mm");
					else
					{
						Format = Format.Parse(hasAmPm ? "h:mm:ss AM/PM" : "h:mm:ss");
					}
				}
				else if (value is FractionExpression && (Format == null || this.Format == Core.Formats.General))
				{
					SetValueAndFormat(v, false);
					Format = Format.Parse("# ?/?");
				}
				else
				{
					SetValueAndFormat(v, forceString);
				}
				//\\SetAutoNumberFormat();
				promote();
                setExpressionValue(null);
				return;
			}
			setExpressionValue(value);
			if (recalc)
				CellFormatter.TrySetReferencedFormat(this, value);
			if (value == null)
			{
				//\\Value = null;
				setRawValue(null);
				return;
			}
			AddDependents();
			if (value is ConstantExpression)
			{
				Value = ((ConstantExpression) value).Value;
				return;
			}
			if (recalc)
				Recalculate();
			promote();
		}
	}
}
